package com.xxm.util

import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.AudioTrack
import android.media.MediaCodec
import android.media.MediaExtractor
import android.media.MediaFormat
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.io.File
import kotlin.math.min

class AudioPlayer {
    private val TAG = "AudioPlayer"
    private var minBufferSize = 0
    private var sampleRate = 44100
    private var channel = AudioFormat.CHANNEL_OUT_DEFAULT
    private var audioFormat = AudioFormat.ENCODING_PCM_16BIT
    private var streamType = AudioManager.STREAM_MUSIC
    private var model = AudioTrack.MODE_STREAM
    private var audioMine = "audio/"

    private var audioTrack: AudioTrack? = null
    private var extractor: MediaExtractor? = null
    private var mediaFormat: MediaFormat? = null
    private var codec: MediaCodec? = null


    fun createPlayer() {
        minBufferSize = AudioTrack.getMinBufferSize(
            sampleRate, //采样 48000
            channel, //声道 4
            audioFormat //编码 2
        )
        Log.d(TAG, "输出最小缓存大小:${minBufferSize}")
        audioTrack = AudioTrack(streamType, sampleRate, channel, audioFormat, minBufferSize, model)
    }


    fun playMp4(path: String) {
        if (!File(path).exists()) {
            Log.e(TAG, "视频不存在")
            return
        }
        GlobalScope.launch(Dispatchers.IO) {
            extractor = MediaExtractor()
            extractor?.setDataSource(path)
            initVideoInfo()
            createPlayer()
            codec = MediaCodec.createDecoderByType(audioMine)
            codec?.configure(mediaFormat, null, null, 0)

            codec?.start()
            audioTrack?.play()


            val bufferInfo = MediaCodec.BufferInfo()
            while (isActive) {
                val index = codec!!.dequeueInputBuffer(1000)
                if (index > 0) {
                    val inputBuffer = codec!!.getInputBuffer(index)
                    val sampleSize = extractor?.readSampleData(inputBuffer!!, 0)
                    sampleSize?.run {
                        if (this < 0) {
                            codec?.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                        } else {

                            codec?.queueInputBuffer(index, 0, sampleSize, extractor!!.sampleTime, 0)
                            extractor?.advance()
                        }
                    }

                }

                var outputIndex = codec!!.dequeueOutputBuffer(bufferInfo, 10000)
                if (outputIndex >= 0) {
                    val outputBuffer = codec!!.getOutputBuffer(outputIndex)
                    val data = ByteArray(bufferInfo.size)
                    outputBuffer?.get(data)
                    audioTrack?.write(data, 0, bufferInfo.size)
                    codec?.releaseOutputBuffer(outputIndex, false)
                }
            }
            release()
        }
    }

     fun release() {
        audioTrack?.stop()
        audioTrack?.release()
        codec?.release()

        minBufferSize = 0
        sampleRate = 44100
        channel = AudioFormat.CHANNEL_OUT_DEFAULT
        audioFormat = AudioFormat.ENCODING_PCM_16BIT
        streamType = AudioManager.STREAM_MUSIC
        model = AudioTrack.MODE_STREAM
        audioMine = "audio/"

        audioTrack = null
        extractor = null
        mediaFormat = null
        codec = null
    }


    private fun initVideoInfo() {
        extractor?.run {
            for (i in 0 until trackCount) {
                 mediaFormat = getTrackFormat(i)
                val mineType = mediaFormat?.getString(MediaFormat.KEY_MIME)
                if (mineType?.startsWith(audioMine) == true) {
                    selectTrack(i)
                    audioMine = mineType
                    sampleRate = mediaFormat!!.getInteger(MediaFormat.KEY_SAMPLE_RATE)
                    val outChannel = mediaFormat!!.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
                    channel = if (outChannel == 1) AudioFormat.CHANNEL_OUT_MONO else AudioFormat.CHANNEL_OUT_STEREO
                    return
                }
            }
        }
    }
}